package com.zjpavt.client.extenddevice.voltagecurrent;

import com.zjpavt.client.enums.ExtendDeviceEnum;
import com.zjpavt.client.event.EventRegisterCenter;
import com.zjpavt.client.extenddevice.AbstractExtendDevice;
import com.zjpavt.client.extenddevice.GpsLigthSensationSensor;
import com.zjpavt.client.extenddevice.gps.IGpsLigthSensationDevcie;
import com.zjpavt.client.extenddevice.lightsensation.ILightSensationDevice;
import com.zjpavt.client.nativemethod.JnIMethod;
import com.zjpavt.client.util.ClientConfig;
import com.zjpavt.client.util.LoggerUtil;
import com.zjpavt.client.util.PropertiesUtil;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class TempratureGpsLightDevice extends AbstractExtendDevice implements IGpsLigthSensationDevcie, ITemperatureAndHumidityDevice {
    private static final ScheduledThreadPoolExecutor schedule = new ScheduledThreadPoolExecutor(1, new DefaultThreadFactory("tempGps"));
    public static final String TEMPERATURE_PATH = ClientConfig.INI_TEMPERATURE_PATH;
    public static final String TMP_SECTION = "tmp_data";
    public static final String TEMPERATURE = "tmp";
    public static final String HUMIDITY = "hum";
    public static final DecimalFormat tmpFormet = new DecimalFormat("#0.0");
    /**
     * 温度值
     */
    private double temperature = 0;
    /**
     * 湿度值
     */
    private double humidity = 0;

    /**
     * 温度阈值的KEY 保存在properties
     */
    public static final String THRESHOLD_PROPERTIES_KEY = "TEMPERATURE_THRESHOLD";

    public static final Pattern TMP_PATTERN =
        Pattern.compile("<AT_T/H_(?<tmp>[0-9]{4})/(?<hum>[0-9]{4})>");


    /**
     * 机柜内启动风扇等措施的阈值
     */
    private volatile int TEMPERATURE_THRESHOLD = 0;

    public TempratureGpsLightDevice(int extNum) {
        super(extNum, ExtendDeviceEnum.GPS_LIGHT);
        getThresholdFromProperties();
        updateTmpInformationTask();
        updateGpsInformationTask();
    }

    private void updateGpsInformationTask() {
        updateGpsInformation();
        schedule.schedule(()-> {
//			如果检查周期小于30S 则不继续更新等待下次
            if (System.currentTimeMillis() - getLastQueryTime() < 30 * 1000) {
            } else {
                updateGpsInformationTask();
            }
        },60, TimeUnit.SECONDS);
    }

    private void updateTmpInformationTask() {
        updateTmpInformation();
        schedule.schedule(()-> {
            updateTmpInformationTask();
        },20, TimeUnit.SECONDS);
    }

    @Override
    public ILightSensationDevice updateLightSensationInformation() {
        return updateGpsInformation();
    }

    @Override
    public TempratureGpsLightDevice updateTmpInformation() {

        String information = JnIMethod.sendMessage2ExtendDeviceByRs485(115200, getExtendNum(), "<AT_READ>", 200);
        if (information == null) {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put(EventRegisterCenter.DEVICE_NAME, ExtendDeviceEnum.TMP.getDeviceName());
            EventRegisterCenter.getInstance().triggerRegisterTask(EventRegisterCenter.DEVICE_DISCONNECT, dataMap);
            return this;
        } else {
            Map<String, Object> data = new HashMap<>();
            data.put(EventRegisterCenter.DEVICE_NAME, ExtendDeviceEnum.TMP.getDeviceName());
            data.put(EventRegisterCenter.EXT_NUM, getExtendNum());
            EventRegisterCenter.getInstance().triggerRegisterTask(EventRegisterCenter.DATA_EXCHANGE,data);
        }
        Matcher matcher = TMP_PATTERN.matcher(information);
        if (matcher.matches()) {
            this.temperature = Double.parseDouble(matcher.group("tmp")) /10;
            this.humidity = Double.parseDouble(matcher.group("hum"))/10;
        } else {
            log.error("update temperature fail");
        }
        return this;
    }


    private void getThresholdFromProperties() {
        String thresholdString = null;
        try {
            thresholdString = PropertiesUtil.getPropertiesDefault(THRESHOLD_PROPERTIES_KEY);
            TEMPERATURE_THRESHOLD = Integer.parseInt(thresholdString);
        } catch (Exception e) {
            log.error("get temperature threshold:" + thresholdString);
        }
    }

    /**
     * 获取温度阈值 单位 1°C
     * @return
     */
    @Override
    public int getTemperatureThreshold() {
        return TEMPERATURE_THRESHOLD;
    }

    /**
     * 获取温度
     * @return
     */
    @Override
    public double getTemperature() {
        return this.temperature;
    }

    /**
     * 获取湿度
     * @return
     */
    @Override
    public double getHumidity() {
        return this.humidity;
    }

    /**
     * 设置温度阈值 单位 1°C
     * @param temperatureThreshold
     */
    @Override
    public synchronized boolean setTemperatureThreshold(double temperatureThreshold) {
        try {
            if (changeTemperatureThreshold((int)temperatureThreshold)) {
                PropertiesUtil.setPropertyOrReplaceDefault(THRESHOLD_PROPERTIES_KEY,String.valueOf(temperatureThreshold));
                TEMPERATURE_THRESHOLD = (int)temperatureThreshold;
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            log.error(LoggerUtil.convertException2String(e));
            return false;
        }
    }

    public static final DecimalFormat TEMPERATURE_THRESHOLD_FORMATE = new DecimalFormat("0000");
    /**
     * @param temperatureThreshold
     */
    private synchronized boolean changeTemperatureThreshold(int temperatureThreshold) {
        String message = "<AT_SET_" + TEMPERATURE_THRESHOLD_FORMATE.format(temperatureThreshold * 10) + ">";
        String setThresholdResult = JnIMethod
                                    .sendMessage2ExtendDeviceByRs485(115200, getExtendNum(), message, 200);
        if (setThresholdResult == null || "".equals(setThresholdResult)) {
            log.error("set temperature threshold fail");
            return false;
        } else {
            log.info("changeTemperatureThreshold: " + setThresholdResult);
            return true;
        }
    }

    private static final Logger logger = LoggerFactory.getLogger(GpsLigthSensationSensor.class);
    /**
     * GPS group name
     */
    private static final String INI_GPS_GROUP = "gps_data";
    /**
     * GPS key
     */
    private static final String INI_GPS_LAT_KEY = "gps_lat";
    /**
     * GPS key
     */
    private static final String INI_GPS_LNG_KEY = "gps_lng";
    private static final int MAX_LATITUDE = 90;
    private static final int MAX_LONGITUDE = 180;
    public static final DecimalFormat LONGITUDE_AND_LATITUDE_FORMATE = new DecimalFormat("#0.0000");
    /**
     * 光照度
     */
    private double lux;
    /**
     * 经度
     */
    private double longitude=120.142743;
    /**
     * 东经/西经
     */
    private char longitedeSymbol = 'E';
    /**
     * 纬度
     */
    private double latitude=30.319629;
    /**
     * 南纬/北纬
     */
    private char latitudeSymbol = 'N';
    /**
     * GPS是否有信号
     */
    private boolean GPSUseful = false;
    public static final Pattern GPS_PATTERN = Pattern.compile("<LUX_GPS_DATA_(?<lux>[0-9.]{1,10})/\\$GNRMC," +
            "(?<time>[0-9.]{10}),(?<useful>[VA]),(?<latitude>[0-9.]{1,12}),(?<lat>[NS])" +
            ",(?<longitude>[0-9.]{1,12}),(?<lng>[EW])[^>]*>");

    public static final Pattern GPS1_PATTERN = Pattern.compile("<LUX_GPS_DATA_(?<lux>[0-9.]{1,10})/GPS_DATA_ERROR>");

    /**
     * 更新设备信息 获取最新的数据
     */
    @Override
    public TempratureGpsLightDevice updateGpsInformation() {

//		如果查询时间小于10秒 则不更新数据
        String gpsInformation = JnIMethod.sendMessage2ExtendDeviceByRs485(115200, getExtendNum(), "<AT_CHECK0_LUX_GPS_DATA>", 200);
        if (gpsInformation == null) {
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put(EventRegisterCenter.DEVICE_NAME, ExtendDeviceEnum.GPS.getDeviceName());
            EventRegisterCenter.getInstance().triggerRegisterTask(EventRegisterCenter.DEVICE_DISCONNECT, dataMap);
            return this;
        } else {
            Map<String, Object> data = new HashMap<>();
            data.put(EventRegisterCenter.DEVICE_NAME, ExtendDeviceEnum.GPS.getDeviceName());
            data.put(EventRegisterCenter.EXT_NUM, getExtendNum());

            EventRegisterCenter.getInstance().triggerRegisterTask(EventRegisterCenter.DATA_EXCHANGE,data);
        }
        Matcher matcher1 = GPS1_PATTERN.matcher(gpsInformation);
        if (matcher1.matches()) {
            this.GPSUseful = false;
            this.lux = Double.parseDouble(matcher1.group("lux"));
            return this;
        }
        Matcher matcher = GPS_PATTERN.matcher(gpsInformation);
        if (matcher.matches()) {
//			刷新更新时间
            setLastQueryTime();
            String useful = matcher.group("useful");
            if ("A".equals(useful)) {
                this.latitude = Double.parseDouble(matcher.group("latitude")) / 100;
                this.longitude = Double.parseDouble(matcher.group("longitede")) / 100;
                this.latitudeSymbol = matcher.group("lat").charAt(0);
                this.longitedeSymbol = matcher.group("lng").charAt(0);
                this.GPSUseful = true;
                matcher.group("time");
            } else {
                this.GPSUseful = false;
            }
            this.lux = Double.parseDouble(matcher.group("lux"));
        } else {
            this.lux = -1;
            this.GPSUseful = false;
        }
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put(EventRegisterCenter.DEVICE_NAME, ExtendDeviceEnum.GPS.getDeviceName());
        dataMap.put(EventRegisterCenter.EXT_NUM, getExtendNum());

        EventRegisterCenter.getInstance().triggerRegisterTask(EventRegisterCenter.DATA_EXCHANGE, dataMap);
        return this;
    }

    public static final DecimalFormat LAT_AND_LNG_FORMAT = new DecimalFormat("#0.000000");
    /**
     * @return 获取格式化后的位置  如12.266E_125.36N
     */
    @Override
    public String returnForFCommand() {
        if (!isGPSUseful()) {
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(LAT_AND_LNG_FORMAT.format(this.longitude))
        .append(longitedeSymbol == 0?"E":longitedeSymbol)
        .append("_")
        .append(LAT_AND_LNG_FORMAT.format(this.latitude))
        .append(latitudeSymbol == 0?"N":latitudeSymbol);
        return  stringBuilder.toString();
    }
    /**
     * 资源互斥通过拓展通道自带的锁实现
     * 尝试通过485获取GPS信号
     * @return
     */
    private static double[] getGpsInfomation() {
        return new double[1];
    }

    @Override
    public boolean isGPSUseful() {
        return GPSUseful;
    }

    @Override
    public double getLux() {
        return lux;
    }

    public static final DecimalFormat LUX_FORMAT = new DecimalFormat("00000");

    /**
     * 返回给P指令使用
     * @return
     */
    @Override
    public String returnForPCommand() {
        return LUX_FORMAT.format(lux);
    }

    @Override
    public IHumidityDevice updateHumidityInformation() {
        return updateTmpInformation();
    }
}
